package org.dyndns.opendemogroup.optimizer.selections;

import static org.junit.Assert.*;

import java.util.Random;

import org.junit.Test;

/**
 * A class to test the class SlidingBias
 */
public class SlidingBiasTest
{

	/**
	 * Tests the <i>pick</i> method with a simulation of a few runs to make
	 * sure that the selections are appropriately distributed.
	 */
	@Test
	public void pick_Simulation ( )
	{
		// { initialization
		// make sure the random number sequence is predictable
		Random randomSource = new Random ( 42 );
		int items = 20;
		int actual;
		int[] maxCounters = new int[items];
		int[] logCounters = new int[items];
		int[] minCounters = new int[items];
		// }

		// { simulation
		for ( int j = 0; j < 10000; j++ )
		{
			for ( int i = 0; i < items; i++ )
			{
				actual = SlidingBias.pick ( randomSource, i, true, items - 1 );
				maxCounters[actual]++;

				actual = SlidingBias.pick ( randomSource, i, false, items - 1 );
				minCounters[actual]++;
			}
		}

		// TODO: Comparing logCounters to maxCounters, we see that the sliding
		// bias is not exactly ln(i) and it does not appear to sum up, either
		for ( int i = 0; i < items; i++ )
		{
			logCounters[i] = (int) ( 10000 * Math.log1p ( i + 1 ) );
		}
		// }

		// { validation
		int currentMax = maxCounters[items - 1];
		int currentLog = logCounters[items - 1];
		int currentMin = minCounters[0];
		for ( int i = 1; i < items; i++ )
		{
			int newMax = maxCounters[items - i - 1];
			int newLog = logCounters[items - i - 1];
			int newMin = minCounters[i];

			assertTrue ( currentMax + " is not greater than " + newMax,
				currentMax > newMax );
			assertTrue ( currentLog + " is not greater than " + newLog,
				currentLog > newLog );
			assertTrue ( currentMin + " is not greater than " + newMin,
				currentMin > newMin );

			currentMax = newMax;
			currentLog = newLog;
			currentMin = newMin;
		}
		// }
	}

}
